# -*- coding:utf-8 -*-
import json
import sys

# @Time    : 2023/8/31 13:54
# @Author  : zengwenjia
# @Email   : zengwenjia@lingxi.ai
# @File    : sales.py
# @Software: LLM_internal

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
from bot.bot import Bot
from loguru import logger
import asyncio
from common import constants
from bot.insurance_consultant.agent.sales_skill_agent import SalesSkill
from bot.insurance_consultant.agent.user_questioning import QuestioningDisputeResolution
from bot.insurance_consultant.agent.user_info_extract import UserInfoExtract
from bot.insurance_consultant.agent.question_solution import QuestionSolution
from bot.insurance_consultant.agent.conversation_agent import Conversation
from bot.insurance_consultant.agent.underwriting_agent import Underwriting


from bot.insurance_consultant.knowledge_base.knowledge_embedding import AZUREQuery
from bot.insurance_consultant.knowledge_question_solution.knowledge_embedding import \
    AZUREQuery as QuestionSolutionAZUREQuery
from bot.insurance_consultant.knowledge_sales_skill.knowledge_embedding import AZUREQuery as SalesSkillAZUREQuery
from bot.insurance_consultant.agent.sales_sop_agent import SalesSop
from bot.insurance_consultant.agent.user_job_agent import UserJob
from bot.insurance_sales_gpt.demo.cache_dict import cache_dict


logger.add("./log/短险执行日志_{time}.log", retention="1 days", format="{time}|{level}|{message}")

class Sales(Bot):
    """销售机器人"""

    # knowledge_base_query = AZUREQuery()
    # knowledge_base_query.load_knowledge_base()
    #
    # knowledge_question_solution_query = QuestionSolutionAZUREQuery()
    # knowledge_question_solution_query.load_knowledge_base()
    #
    # knowledge_sale_skill_query = SalesSkillAZUREQuery()
    # knowledge_sale_skill_query.load_knowledge_base()

    def __init__(self):
        self.user_info = ''
        self.solution = ""
        self.max_token_length = 1024 * 3
        self.role_name = "保险规划师"
        self.business_background = """保险公司:泰康保险
赠险产品:交通意外险
销售产品:百万医疗险
赠险领取方式:通过"如果有保"公众号"""
        self.model_name = "gpt"
        self.user_job = ''
        self.process_knowledge = ''
        self.multi_knowledge = ''
        self.user_question = ''
        self.skill = ''
        self.sop = ''
        self.content = ''
        self.underwriting = ''

    def format_conversation_history(self, conversation_context, max_token_length=None):
        dialogue_history = ""
        if (not max_token_length) or (max_token_length > self.max_token_length):
            max_token_length = self.max_token_length
        # 倒序遍历record_list
        for record in conversation_context[::-1]:
            next_dialogue_history = dialogue_history
            if record['role'] == constants.ROLE_USER:
                next_dialogue_history = "用户:" + record["content"] + "\n" + dialogue_history
            elif record['role'] == constants.ROLE_ASSISTANT:
                next_dialogue_history = self.role_name + ":" + record["content"] + "\n" + dialogue_history
            if len(next_dialogue_history) > max_token_length:
                break
            else:
                dialogue_history = next_dialogue_history
        return dialogue_history

    async def get_user_question(self):
        try:
            questioning_dispute_resolution = QuestioningDisputeResolution(self.role_name, self.conversation_history_str,
                                                                          self.user_base_info)
            self.user_question = await questioning_dispute_resolution.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-用户疑义是:{self.user_question}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.user_question = ""

    async def extract_user_info(self):
        try:
            user_info_extract = UserInfoExtract(self.role_name, self.conversation_history_str, self.user_base_info)
            self.user_info = await user_info_extract.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-用户情境是:{self.user_info}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.user_info = ""

    async def get_sales_sop(self):
        """
        销售流程
        判断下一步的销售流程节点
        """
        try:
            sales_sop = SalesSop(self.role_name, self.conversation_history_str)
            self.sop = await sales_sop.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-销售流程节点是:{self.sop}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.sop = ""

    async def get_user_job(self):
        """
        获取用户目标
        分析用户当前的职业风险(压力、工作环境、意外风险、作息时间等)、生活习惯(抽烟、喝酒、熬夜、饮食)
        由于这些风险会(对自己\对家人)造成什么影响
        """
        skip_user_job_sop = [
            '收集用户情境',
            '用户自身问题分析',
            '协助投保',
            '促成',
            '加保拖单',
        ]
        if self.sop not in skip_user_job_sop:
            self.user_job = ''
            return
        try:
            user_job = UserJob(self.role_name, self.business_background, self.user_base_info, self.user_info,
                               self.conversation_history_str)
            self.user_job = await user_job.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-用户目标是:{self.user_job}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.sop = ""

    async def question_solution(self):
        """
        用户疑义解答
        """
        if self.user_question == '用户无问题':
            return
        try:
            similarity_knowledge = self.knowledge_question_solution_query.search_with_score("用户疑义:" +
                                                                                                 self.user_question,
                                                                                                 top_k=3,
                                                                                                 limit_score=0.8)
            similarity_knowledge.extend(self.knowledge_base_query.search_with_score(self.user_question, top_k=1,
                                                                               limit_score=0.8))
            logger.info(f"session_id:{self.session_id},content:{self.content},embedding-用户疑义是:{similarity_knowledge}")
            multi_knowledge = ''
            if similarity_knowledge:
                for item in similarity_knowledge:
                    multi_knowledge += item.metadata['text'] + '\n---\n'
                    if len(multi_knowledge) > 1024:
                        break
            self.multi_knowledge = multi_knowledge.rstrip('---\n')
            question_solution = QuestionSolution(self.role_name,
                                                 self.business_background,
                                                 self.user_base_info,
                                                 self.user_info,
                                                 self.user_question,
                                                 self.multi_knowledge,
                                                 self.conversation_history_str)
            self.solution = await question_solution.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-用户疑义解答是:{self.solution}")
            return self.solution
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.solution = ""

    async def sales_skill(self):
        """
        销售技巧
        输入销售流程节点
        获取流程话术
        """
        try:
            similarity_knowledge = self.knowledge_sale_skill_query.search_with_score("销售流程节点:" + self.sop,
                                                                               top_k=1,
                                                                               limit_score=0.8)
            similarity_knowledge.extend(self.knowledge_base_query.search_with_score("销售流程节点:" +
                                                                                                    self.sop,
                                                                               top_k=1,
                                                                               limit_score=0.8))
            logger.info(f"session_id:{self.session_id},content:{self.content},embedding-销售流程是:{similarity_knowledge}")
            skill_knowledge = ''
            if similarity_knowledge:
                for item in similarity_knowledge:
                    skill_knowledge += item.metadata['text'] + '\n---\n'
            self.skill_knowledge = skill_knowledge.rstrip('---\n')
            sales_skill = SalesSkill(
                self.role_name,
                self.business_background,
                self.conversation_history_str,
                self.user_base_info,
                self.user_info,
                self.sop,
                self.skill_knowledge)
            self.skill = await sales_skill.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-销售流程话术是:{self.skill}")
            # self.process_knowledge = get_sales_skill_utter(self.skill)
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.skill = ""

    async def perform_underwriting(self):
        """
        核保
        检查是否是高危职业、两年内住过院、是否有重大疾病
        投保前检查是否有核保信息,没有核保信息生成核保话术
        """
        skip_underwriting_sop = [
            '收集用户情境',
            '确认费用',
            '协助投保',
            '加保拖单',
        ]
        if self.sop not in skip_underwriting_sop:
            self.underwriting = '符合投保条件'
            return
        try:
            underwriting = Underwriting(self.role_name, self.user_base_info, self.user_info, self.conversation_history_str, self.sop)
            self.underwriting = await underwriting.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-核保结果是:{self.underwriting}")
        except Exception as e:
            # 打印错误的堆栈信息
            logger.exception(e)
            self.underwriting = ""


    async def generate_reply(self):
        """
        生成最终话术
        """
        try:
            conversation = Conversation(self.role_name,
                                        self.business_background,
                                        self.conversation_history_str, self.user_question, self.solution,
                                        self.sop,
                                        self.skill,
                                        self.user_job,
                                        self.underwriting)
            result = await conversation.achat_auto_llm(type=self.model_name)
            logger.info(f"session_id:{self.session_id},content:{self.content},agent-话术生成是:{result}")
            return result
        except Exception as e:
            logger.exception(e)
            return "出错了，我不知道怎么回答你的问题，你可以换个问法试试"

    async def async_reply(self, context, session_id, name='王先生', user_base_info='性别:男\n年龄:37\n城市:包头', content=''):
        conversation = self.format_conversation_history(context)
        # logger.info("conversation is " + str(conversation) + " session_id is " + str(session_id))
        self.session_id = session_id
        self.context = context
        self.conversation_history_str = conversation
        self.user_base_info = user_base_info
        self.content = content
        if f'cache_user_info:{session_id}' in cache_dict:
            self.user_info = cache_dict[f'cache_user_info:{session_id}']
        if len(self.context) > 1:
            # 用户情境\用户疑义\销售流程
            info_task = asyncio.create_task(self.extract_user_info())
            user_question_task = asyncio.create_task(self.get_user_question())
            sales_sop_task = asyncio.create_task(self.get_sales_sop())
            await asyncio.gather(info_task, user_question_task, sales_sop_task)

            # 用户目标\异议解答\销售技巧\核保
            user_job = asyncio.create_task(self.get_user_job())
            question_solution_task = asyncio.create_task(self.question_solution())
            sales_skill_task = asyncio.create_task(self.sales_skill())
            underwriting_task = asyncio.create_task(self.perform_underwriting())

            await asyncio.gather(user_job, question_solution_task, sales_skill_task,underwriting_task)

        else:
            self.background_knowledge = ""
            self.skill = f"喂，您好，请问您是{name}吗？"
            self.solution = ""
        result = await self.generate_reply()
        logger.info(f"session_id:{self.session_id},最终生成话术是:{result}")
        cache_dict[f'cache_user_info:{session_id}'] = self.user_info
        logger.info(f"---------------分割线--------------")
        return result


class SaleGPT:
    def reply(self, query, session_id=None, user_base_info=None):
        if session_id not in cache_dict:
            cache_dict[session_id] = []
        conversation_history = cache_dict.get(session_id)
        if len(conversation_history) > 0:
            conversation_dict = {}
            conversation_dict["role"] = "user"
            conversation_dict["content"] = query
            cache_dict[session_id].append(conversation_dict)

        sales = Sales()
        if user_base_info:
            sales.user_base_info=user_base_info
        result = asyncio.run(sales.async_reply(conversation_history, session_id, content=query))
        conversation_dict = {}
        conversation_dict["role"] = "assistant"
        conversation_dict["content"] = result
        cache_dict[session_id].append(conversation_dict)
        return result


if __name__ == '__main__':
    conversation_history = [
    ]
    sales = Sales()
    result = asyncio.run(sales.async_reply(conversation_history, "123"))






    # while True:
    #     sales = Sales()
    #     result = asyncio.run(sales.async_reply(conversation_history, "123"))
    #     conversation_dict = {}
    #     conversation_dict["role"] = "assistant"
    #     conversation_dict["content"] = result
    #     conversation_history.append(conversation_dict)
    #     logger.info('历史对话缓存:{}'.format(conversation_history))
    #     print(result)
    #     user_input = input("请输入用户的对话：")
    #     conversation_dict = {}
    #     conversation_dict["role"] = "user"
    #     conversation_dict["content"] = user_input
    #     conversation_history.append(conversation_dict)
